import pika
import logging
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class RabbitMQClient:
    def __init__(self, host, port, username, password):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.connection = None
        self.channel = None
        self.consumer_tags = {}  # 用于存储消费者标签及其相关信息

    def connect(self):
        """建立与RabbitMQ的连接"""
        credentials = pika.PlainCredentials(self.username, self.password)
        parameters = pika.ConnectionParameters(self.host, self.port, '/', credentials)
        self.connection = pika.BlockingConnection(parameters)
        self.channel = self.connection.channel()
        logger.info("Connected to RabbitMQ server")

    def close(self):
        """关闭连接"""
        if self.connection and self.connection.is_open:
            self.connection.close()
            logger.info("Connection closed")

    def declare_queue(self, queue_name, durable=False):
        """声明一个队列"""
        self.channel.queue_declare(queue=queue_name, durable=durable)
        logger.info(f"Queue '{queue_name}' declared")

    def declare_exchange(self, exchange_name, exchange_type='direct', durable=False):
        """声明一个交换机"""
        self.channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type, durable=durable)
        logger.info(f"Exchange '{exchange_name}' declared with type '{exchange_type}'")

    def bind_queue_to_exchange(self, queue_name, exchange_name, routing_key=''):
        """将队列绑定到交换机"""
        self.channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key)
        logger.info(f"Queue '{queue_name}' bound to exchange '{exchange_name}' with routing key '{routing_key}'")

    def publish(self, queue_name, message):
        """发布消息到指定队列"""
        self.channel.basic_publish(exchange='', routing_key=queue_name, body=message)
        logger.info(f"Message sent to queue '{queue_name}': {message}")

    def publish_to_exchange(self, exchange_name, routing_key, message):
        """发布消息到指定交换机"""
        self.channel.basic_publish(exchange=exchange_name, routing_key=routing_key, body=message)
        logger.info(f"Message sent to exchange '{exchange_name}' with routing key '{routing_key}': {message}")

    def start_consuming(self, queue_name, callback, auto_ack=False, consumer_tag=None):
        """启动消费者线程"""
        try:
            if not consumer_tag:
                consumer_tag = f'ctag_{queue_name}_{int(time.time())}'  # 生成一个唯一的消费者标签
            consumer_tag = self.channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=auto_ack, consumer_tag=consumer_tag)
            self.consumer_tags[consumer_tag] = {'queue': queue_name, 'callback': callback}  # 保存消费者标签及其相关信息
            logger.info(f"Consuming messages from queue '{queue_name}' with consumer tag: {consumer_tag}")
            self.channel.start_consuming()
        except Exception as e:
            logger.error(f"Error starting consumer: {e}")
            self.stop_consuming()

    def stop_consuming(self):
        """停止消费者"""
        if self.channel:
            try:
                for consumer_tag in list(self.consumer_tags.keys()):
                    self.channel.basic_cancel(consumer_tag=consumer_tag)  # 取消消费者标签
                    del self.consumer_tags[consumer_tag]  # 从字典中删除消费者标签
                self.channel.stop_consuming()
                logger.info("Consumer stopped")
            except Exception as e:
                logger.error(f"Error stopping consumer: {e}")

# 定义回调函数
def my_callback(ch, method, properties, body):
    ch.basic_ack(delivery_tag=method.delivery_tag)
    logger.info(f"Received message: {body.decode()}")
    # 在这里处理接收到的消息
    # 如果需要确认消息，可以使用以下代码
    print(body.decode() + "消息")

if __name__ == "__main__":
    # 创建自定义RabbitMQ客户端实例
    rabbitmq_client = RabbitMQClient("localhost", 5672, "guest", "guest")

    try:
        # 连接到RabbitMQ
        rabbitmq_client.connect()

        # 声明交换机
        exchange_name = 'my_exchange'
        rabbitmq_client.declare_exchange(exchange_name, exchange_type='direct', durable=True)

        # 声明队列
        queue_name = 'hello'
        rabbitmq_client.declare_queue(queue_name, durable=True)

        # 绑定队列到交换机
        rabbitmq_client.bind_queue_to_exchange(queue_name, exchange_name, routing_key='hello_key')

        # 启动自定义消费者
        rabbitmq_client.start_consuming(queue_name, my_callback)

        # 发布消息到交换机
        message = "Hello, RabbitMQ via Exchange!"
        rabbitmq_client.publish_to_exchange(exchange_name, 'hello_key', message)

        # 保持主线程运行
        while True:
            time.sleep(1)

    except KeyboardInterrupt:
        logger.info("Interrupted by user")
    finally:
        # 停止消费者
        rabbitmq_client.stop_consuming()
        # 关闭连接
        rabbitmq_client.close()
